from numpy import *
import operator
from os import listdir
from common import tool


# read data
def file2Matrix(file):  # read file to matrix
    fr = open(file).readlines()
    lines = len(fr)  # get line number
    retMat = zeros((lines, 3))  # prepare a matrix
    labels = []
    index = 0
    for x in fr:  # x is line content
        x = x.strip()
        arr = x.split('\t')  # split string
        retMat[index, :] = arr[0:3]
        index += 1
        labels.append(int(arr[-1]))
    return retMat, labels


# standardization
def autoNorm(mat):
    minVals = mat.min(0)
    maxVals = mat.max(0)
    scope = maxVals - minVals
    newMat = zeros(shape(mat))
    s = (newMat.shape[0], 1)
    newMat = mat - tile(minVals, s)
    newMat = newMat / tile(scope, s)
    return newMat, scope, minVals


# classify
# inMat specify data, mat feature set, label: feature set result, k: from k element get max label
def classify(inMat, mat, label, k):
    m = mat.shape[0]
    temp = tile(inMat, (m, 1))
    temp = (temp - mat) ** 2
    distance = temp.sum(axis=1) ** 0.5
    distanceIndicies = distance.argsort()
    clss = {}
    for i in range(k):
        voteLabel = label[distanceIndicies[i]]
        clss[voteLabel] = clss.get(voteLabel, 0) + 1
    sortClss = sorted(clss.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortClss[0][0]


def testClassifyPerson():
    featrue = array([36990, 10, 0.1])
    mat, label = file2Matrix('datingTestSet2.txt')
    newMat, scope, minVal = autoNorm(mat)
    mormalFeatrue = (featrue - minVal) / scope
    result = classify(mormalFeatrue, newMat, label, 200)
    print "result: %d " % result
    tool.show(mat, label, featrue)


# test
def testDating():
    testRatio = 0.1
    mat, label = file2Matrix('datingTestSet2.txt')
    newMat = autoNorm(mat)
    m = newMat.shape[0]
    testNum = int(m * testRatio)
    errorCount = 0.0
    for i in range(testNum):
        outLabel = classify(newMat[i, :], newMat[testNum:m, :], label[testNum:m], 10)
        if (outLabel != label[i]):
            errorCount += 1.0
        print "except:%d , real:%d" % (outLabel, label[i])
    print "errorCount: %d, errorRatio=%f" % (errorCount, (errorCount / float(testNum)))


# 2 convert file to number
def img2vector(filename):
    contents = open(filename)
    vector = zeros((1, 1024))
    for i in range(32):
        line = contents.readline()
        for j in range(32):
            vector[0, 32 * i + j] = int(line[j])
    return vector


# 2 test identify number
def testClassifyNumber():
    labels = []
    matlist = listdir('trainingDigits')
    m = len(matlist)
    mat = zeros(([m, 1024]))
    for i in range(m):
        filenameStr = matlist[i]
        filename = filenameStr.split('.')[0]
        label = int(filename.split('_')[0])
        labels.append(label)
        vetor = img2vector('trainingDigits/%s' % filenameStr)
        mat[i, :] = vetor
    testList = listdir('testDigits')
    n = len(testList)
    excepts = []
    errorCount = 0.0
    for j in range(n):
        filenameStr = testList[j]
        filename = filenameStr.split('.')[0]
        label = int(filename.split('_')[0])
        excepts.append(label)
        testData = img2vector('testDigits/%s' % filenameStr)
        result = classify(testData, mat, labels, 3)
        if result != label:
            print "error.except: %d, real: %d" % (result, label)
            errorCount += 1.0
        else:
            print "except: %d, real: %d" % (result, label)
    print "errorCount: %d, errorRatio: %f" % (errorCount, errorCount / float(n))


# testDating()
testClassifyPerson()
#testClassifyNumber()
